package com.example.demo.model.page;

import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.collections4.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 分页类
 * T0返回类型，T1请求类型
 *
 * @author Liunh
 */
public class Page<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 默认开始行
     */
    @ApiModelProperty(name = "DEFAULT_START", value = "默认开始行", example = "0")
    public static int DEFAULT_START = 0;

    /**
     * 默认每页显示行数
     */
    @ApiModelProperty(name = "DEFAULT_LIMIT", value = "默认每页显示行数", example = "1")
    public static int DEFAULT_LIMIT = 20;

    /**
     * 默认页
     */
    @ApiModelProperty(name = "DEFAULT_PAGE", value = "默认页", example = "1")
    public static int DEFAULT_PAGE = 1;
    /**
     * 第一页
     */
    @ApiModelProperty(name = "pageNumber", value = "第一页", example = "1")
    private final int firstPage = 1;
    /**
     * 当前页数
     */
    @ApiModelProperty(name = "pageNumber", value = "当前页数", example = "1")
    private long pageNumber;
    /**
     * 最后一页
     */
    @ApiModelProperty(name = "lastPage", value = "最后一页", example = "1")
    private long lastPage;

    /**
     * 每页显示条数
     */
    @ApiModelProperty(name = "pageSize", value = "每页显示条数", example = "1")
    private int pageSize;

    /**
     * 每页起始行号
     */
    @ApiModelProperty(name = "startRow", value = "每页起始行号", example = "1")
    private long startRow;

    /**
     * 每页结束行号
     */
    @ApiModelProperty(name = "endRow", value = "每页结束行号", example = "1")
    private long endRow;

    /**
     * 总行数
     */
    @ApiModelProperty(name = "total", value = "总行数", example = "1")
    private long total;

    /**
     * 总页数
     */
    @ApiModelProperty(name = "pages", value = "总页数", example = "1")
    private long pages;

    /**
     * 查询条件
     */
    @ApiModelProperty(name = "condition", value = "查询条件")
    private Object condition;

    /**
     * key:排序字段
     * value:排序方式
     * example = "{\"createTime\":\"DESC\",\"id\":\"ASC\"}"
     */
    @ApiModelProperty(name = "sort", value = "排序条件")
    private Map<String, SortReq.SortType> sort;

    /**
     * 查询结果
     */
    @ApiModelProperty(name = "result", value = "查询结果")
    private List<T> result = Collections.emptyList();

    public Page() {
        //默认开始行
        this.startRow = DEFAULT_START;
        //默认每页显示行数
        this.pageSize = DEFAULT_LIMIT;
        //默认页
        this.pageNumber = DEFAULT_PAGE;
    }

    public Page(long page, int size) {
        this.pageNumber = page;
        this.pageSize = size;
        this.endRow = page * Long.parseLong(String.valueOf(size));
        this.startRow = this.endRow - Long.parseLong(String.valueOf(size));
    }

    public Page(List<T> result, long page, int size, long total) {
        //this.fixEndRow(page, size, total);
        this.result = result;
        this.pageNumber = page;
        this.pageSize = size;
        this.total = total;
    }

    public Page(List<T> result, Object condition, long page, int size, long total) {
        //this.fixEndRow(page, size, total);
        this.result = result;
        //this.condition = condition;
        this.pageNumber = page;
        this.pageSize = size;
        this.total = total;
    }

    public Page(long page, int size, long total) {
        //this.fixEndRow(page, size, total);
        this.pageNumber = page;
        this.pageSize = size;
        this.setTotal(total);
        this.getStartRow();
    }

    private void fixEndRow(long page, int size, long total) {
        if (page < 1) {
            page = DEFAULT_PAGE;
        }
        this.pageNumber = page;
        if (size < 1) {
            size = DEFAULT_LIMIT;
        }
        if (total < 1) {
            total = 0;
        }
        this.endRow = page * Long.parseLong(String.valueOf(size));
        this.startRow = this.endRow - Long.parseLong(String.valueOf(size));
        long mod = total % Long.parseLong(String.valueOf(size));
        this.pages = total / Long.parseLong(String.valueOf(size));
        if (page == 1) {
            this.startRow = 0;
            if (mod > 0) {
                this.pages = this.pages + 1;
            }
            if (this.endRow > total) {
                this.endRow = total;
                this.pages = 1;
            }
        } else {
            if (mod > 0) {
                this.pages = this.pages + 1;
            }
            if (this.endRow > total) {
                this.startRow = total - mod;
                this.endRow = total;
            }
        }
        this.lastPage = pages;
        if (this.pageNumber > this.lastPage && this.lastPage > 0) {
            this.pageNumber = this.lastPage;
        }
        this.total = total;
    }

    public Map<String, SortReq.SortType> getSort() {
        return sort;
    }

    public Page<T> setSort(Map<String, SortReq.SortType> sort) {
        this.sort = sort;
        return this;
    }

    public long getPageNumber() {
        this.setPageNumber(this.pageNumber);
        return this.pageNumber;
    }

    public Page<T> setPageNumber(long page) {
        /*if (page < 1) {
            page = DEFAULT_PAGE;
        }
        if (this.pages > 0 && page > this.pages) {
            page = this.pages;
        }
        if (this.lastPage > 0 && page > this.lastPage) {
            page = this.lastPage;
        }
        if (this.total > 0 && this.pageSize > 0) {
            long mod = this.total % Long.parseLong(String.valueOf(this.pageSize));
            this.pages = this.total / Long.parseLong(String.valueOf(this.pageSize));
            if (mod > 0) {
                this.pages = this.pages + 1;
            }
            if (page > this.pages) {
                page = this.pages;
            }
        }*/
        this.pageNumber = page;
        return this;
    }

    public int getPageSize() {
        this.setPageSize(this.pageSize);
        return this.pageSize;
    }

    public Page<T> setPageSize(int size) {
        if (this.total > 0 && size > this.total) {
            size = Integer.parseInt(String.valueOf(this.total));
        }
        this.pageSize = size;
        return this;
    }

    public long getStartRow() {
        if (this.pageSize < 1) {
            this.pageSize = DEFAULT_LIMIT;
        }
        if (this.pageNumber <= 1) {
            this.startRow = 0;
        } else {
            this.startRow = this.pageNumber * Long.parseLong(String.valueOf(this.pageSize)) - this.pageSize + 1;
        }
        if (this.total > 0 && this.pageSize > 0) {
            long mod = this.total % Long.parseLong(String.valueOf(this.pageSize));
            if (this.startRow + mod > this.total) {
                this.startRow = this.total - mod;
            }
        }
        return this.startRow;
    }

    public Page<T> setStartRow(long startRow) {
        if (startRow < 1) {
            startRow = 0;
        }
        if (this.total > 0) {
            long mod = this.total % Long.parseLong(String.valueOf(this.pageSize));
            if (startRow + mod > this.total) {
                startRow = this.total - mod;
            }
        }
        this.startRow = startRow;
        return this;
    }

    public long getEndRow() {
        if (this.pageSize > 0) {
            this.endRow = this.startRow + this.pageSize;
        }
        if (this.total > 0 && this.endRow > this.total) {
            this.endRow = this.total;
        }
        return this.endRow;
    }

    public Page<T> setEndRow(long endRow) {
        if (endRow < 1) {
            endRow = 0;
        }
        if (this.total > 0 && endRow > this.total) {
            endRow = this.total;
        }
        this.endRow = endRow;
        return this;
    }

    public long getTotal() {
        if (this.total < 1) {
            this.total = 0;
        }
        return this.total;
    }

    public Page<T> setTotal(long total) {
        if (total < 1) {
            total = 0;
        }
        this.total = total;
        if (this.pageSize < 1) {
            this.pageSize = DEFAULT_LIMIT;
        }
        this.pages = total / Long.parseLong(String.valueOf(this.pageSize));
        long mod = total % Long.parseLong(String.valueOf(this.pageSize));
        if (mod > 0) {
            this.pages = this.pages + 1;
        }
        if (total > 0 && this.endRow > total) {
            this.endRow = this.total;
        } else {
            if (this.pageNumber <= 1) {
                this.endRow = this.pageSize;
            } else {
                long endRow1 = this.pageNumber * this.pageSize;
                this.endRow = endRow1 > total ? total : endRow1;
            }
        }
        this.lastPage = this.pages;
        if (this.pageNumber > 0 && this.pageNumber > this.lastPage && this.lastPage > 0) {
            this.pageNumber = this.lastPage;
        }
        return this;
    }

    public long getPages() {
        if (this.total < 1) {
            this.total = 0;
        }
        if (this.pageSize < 1) {
            this.pageSize = DEFAULT_LIMIT;
        }
        this.pages = this.total / Long.parseLong(String.valueOf(this.pageSize));
        long mod = this.total % Long.parseLong(String.valueOf(this.pageSize));
        if (mod > 0) {
            this.pages = this.pages + 1;
        }
        return this.pages;
    }

    public Page<T> setPages(long pages) {
        if (pages < 1) {
            pages = 1;
        }
        if (this.total > 0 && this.pageSize > 0) {
            long pagesTmp = this.total / Long.parseLong(String.valueOf(this.pageSize));
            if (pages > pagesTmp) {
                long mod = this.total % Long.parseLong(String.valueOf(this.pageSize));
                if (mod > 0) {
                    pages = pagesTmp + 1;
                } else {
                    pages = pagesTmp;
                }
            }
        }
        this.pages = pages;
        this.lastPage = pages;
        return this;
    }

    public long getLastPage() {
        this.lastPage = this.getPages();
        return lastPage;
    }

    public Page<T> setLastPage(long lastPage) {
        if (lastPage < 1) {
            lastPage = 1;
        }
        this.pages = lastPage;
        this.lastPage = lastPage;
        return this;
    }

    public int getFirstPage() {
        return firstPage;
    }

    /**
     * startRow 和 endRow 又计算得到
     * public Page<T> setStartRow(long startRow) {
     * this.startRow = startRow;
     * return this;
     * }
     * public Page<T> setEndRow(long endRow) {
     * this.endRow = endRow;
     * return this;
     * }
     */

    public List<T> getResult() {
        if (CollectionUtils.isEmpty(this.result)) {
            this.result = new ArrayList<>();
        }
        return this.result;
    }

    public Page<T> setResult(List<T> result) {
        this.result = result;
        return this;
    }

    public Object getCondition() {
        return condition;
    }

    public void setCondition(Object reqClass) {
        this.condition = reqClass;
    }

}